package io.noties.markwon.base.html


import io.noties.markwon.base.html.video.VideoSpanFactory
import io.noties.markwon.base.html.iframe.Iframe
import io.noties.markwon.base.html.iframe.IframeSpanFactory
import io.noties.markwon.base.image.size.ImageAutoSizeShowResolverDef
import io.noties.markwon.base.html.MarkwonHtmlParserFormatImpl.SampleBlockHandler
import io.noties.markwon.base.*
import io.noties.markwon.base.html.tag.*
import io.noties.markwon.base.html.video.Video
import org.commonmark.node.HtmlBlock
import org.commonmark.node.HtmlInline
import org.commonmark.node.Node
import java.lang.IllegalStateException

/**
 * @since 3.0.0
 */
class HtmlFormatPlugin constructor(var htmlParser: MarkwonHtmlParser) :
    AbstractMarkwonPlugin() {
    /**
     * @see .create
     * @since 4.0.0
     */
    interface HtmlConfigure {
        fun configureHtml(plugin: HtmlFormatPlugin)
    }

    private val builder: MarkwonHtmlRendererImpl.Builder = MarkwonHtmlRendererImpl.Builder()
    private var htmlRenderer: MarkwonHtmlRenderer? = null

    // @since 4.4.0
    private var emptyTagReplacement = HtmlEmptyTagFormatReplacement()

    /**
     * @param allowNonClosedTags whether or not non-closed tags should be closed
     * at the document end. By default `false`
     * @since 4.0.0
     */
    fun allowNonClosedTags(allowNonClosedTags: Boolean): HtmlFormatPlugin {
        builder.allowNonClosedTags(allowNonClosedTags)
        return this
    }

    /**
     * @since 4.0.0
     */
    fun addHandler(tagHandler: TagHandler): HtmlFormatPlugin {
        builder.addHandler(tagHandler)
        return this
    }

    /**
     * @since 4.0.0
     */
    fun getHandler(tagName: String): TagHandler? {
        return builder.getHandler(tagName)
    }

    /**
     * Indicate if HtmlPlugin should register default HTML tag handlers. Pass `true` to **not**
     * include default handlers. By default default handlers are included. You can use
     * [TagHandlerNoOp] to no-op certain default tags.
     *
     * @see TagHandlerNoOp
     *
     * @since 4.0.0
     */
    fun excludeDefaults(excludeDefaults: Boolean): HtmlFormatPlugin {
        builder.excludeDefaults(excludeDefaults)
        return this
    }

    /**
     * @param emptyTagReplacement [HtmlEmptyTagReplacement]
     * @since 4.4.0
     */
    fun emptyTagReplacement(emptyTagReplacement: HtmlEmptyTagFormatReplacement): HtmlFormatPlugin {
        this.emptyTagReplacement = emptyTagReplacement
        return this
    }

    fun htmlParser(htmlParser: MarkwonHtmlParser): HtmlFormatPlugin {
        this.htmlParser = htmlParser
        return this
    }


    /*@Override
    public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
        super.configureTheme(builder);
        builder.headingTextSizeMultipliers(FORMAT_HEADING_SIZES);
    }
*/
    override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
        super.configureSpansFactory(builder)
        builder.setFactory(Video::class.java, VideoSpanFactory())
        builder.setFactory(Iframe::class.java, IframeSpanFactory())
    }

    override fun configureConfiguration(configurationBuilder: MarkwonConfiguration.Builder) {

        // @since 4.0.0 we init internal html-renderer here (marks the end of configuration)
        configurationBuilder.imageSizeResolver(ImageAutoSizeShowResolverDef())
        if (!builder.excludeDefaults()) {
            // please note that it's better to not checkState for
            // this method call (minor optimization), final `build` method call
            // will check for the state and throw an exception if applicable
            builder.addDefaultTagHandler(ImageHandler.create())
            builder.addDefaultTagHandler(VideoHandler())
            builder.addDefaultTagHandler(IframeHandler())
            builder.addDefaultTagHandler(LinkHandler())
            builder.addDefaultTagHandler(BlockquoteHandler())
            builder.addDefaultTagHandler(SubScriptHandler())
            builder.addDefaultTagHandler(SuperScriptHandler())
            builder.addDefaultTagHandler(StrongEmphasisHandler())
            builder.addDefaultTagHandler(StrikeHandler())
            builder.addDefaultTagHandler(UnderlineHandler())
            builder.addDefaultTagHandler(ListHandler())
            builder.addDefaultTagHandler(EmphasisHandler())
            builder.addDefaultTagHandler(HeadingHandler())
        }
        htmlParser = MarkwonHtmlParserFormatImpl.create(SampleBlockHandler())
        htmlRenderer = builder.build()
    }

    override fun afterRender(node: Node, visitor: MarkwonVisitor) {
        if (htmlRenderer != null) {
            htmlRenderer!!.render(visitor, htmlParser)
        } else {
            throw IllegalStateException("Unexpected state, html-renderer is not defined")
        }
    }

    override fun configureVisitor(builder: MarkwonVisitor.Builder) {
        builder.on(HtmlBlock::class.java) { visitor, htmlBlock ->
            visitHtml(
                visitor,
                htmlBlock.literal
            )
        }
            .on(HtmlInline::class.java) { visitor, htmlInline ->
                visitHtml(
                    visitor,
                    htmlInline.literal
                )
            }
    }

    private fun visitHtml(visitor: MarkwonVisitor, html: String?) {
        if (html != null) {
            htmlParser.processFragment(visitor.builder(), html)
        }
    }

    companion object {
        /*fun create(): HtmlFormatPlugin {
            return HtmlFormatPlugin()
        }*/

        fun create(htmlParser: MarkwonHtmlParser): HtmlFormatPlugin {
            return HtmlFormatPlugin(htmlParser)
        }

        /**
         * @since 4.0.0
         */
        /*fun create(configure: HtmlConfigure): HtmlFormatPlugin {
            val plugin = create()
            configure.configureHtml(plugin)
            return plugin
        }*/

    }
}